package com.vict.util;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
 *
 */
public class StAPIYQTest {


	private static String charset = "GBK";

	//签名服务器
//	private static String signIP = "192.168.0.94";
	private static String signIP = "192.168.0.81";
	private static int signport = 8010;

	//SSL服务器的url
//	private static String SSLUrl = "http://192.168.0.94:7071/yqbank/APIReqServlet";
	private static String SSLUrl = "http://192.168.0.81:7071/yqbank/APIReqServlet";



	public static void main(String[] args) throws Exception {
		//银行编号（CCC）：867
		//银企客户号（cstNo）：100000010650
		//银企用户号（userNo）：110692
		//银企编号（userId）：88
		//
		//总公司账号：047101012000059844
		//户名：内骐纯猎硼建材有限公司
		//
		//子公司账号：047101012000060313
		//户名：内骐纯缅迂豳虬农业科技有限公司

		//生产
		//银行编号（CCC）：867
		//银企客户号（cstNo）：100000060466
		//银企用户号（userNo）：152354
		//银企编号（userId）：FQ
		//
		//账号：867200501421000312
		//户名：内蒙古柒个贰航空旅游有限公司


		//银行编号（CCC）
		String ccc = "867";
		//客户号
		String cstNo = "100000060466";
		//网银中合法的企业操作员号
		String userNo = "152354";
		//客户Id标识
		String userId = "FQ";
		//账号：
		String accountNo = "867200501421000312";
		//获取当前时间
		String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
		System.out.println(now);
		//交易名称：请求的方法名称：enterpriseQry(查询账户的余额) queryAccHisDetail(查询账户的交易明细)
		String opname = "queryAccHisDetail";
		//客户端唯一标识单笔指令序号 YYYYMMDDHHMMSSCCCXXYYYY
		//YYYYMMDD 年月日HHMMSS 小时分钟秒; CCC 银行提供的固定编号; XX 银行为企业编号分配的两位编号; YYYY 四位的顺序号(随便写)
		//（客户端唯一标识单笔指令序号）
		String serialNo = now + ccc + userId + "1234";
		System.out.println("serialNo:"+serialNo);

		//客户端请求时间（yyyymmddhhmmss）
		String reqTime = now;
		//开始时间
		String beginDate = "20230509";
		//结束时间
		String endDate = "20230628";



		//生成签名密文
//		String opreq = "<opReq><opname>enterpriseAccPay</opname><cstNo>100000003043</cstNo><userNo>103135</userNo><serialNo>20191011095944816RY1234</serialNo><userId>RY</userId><reqTime>20191011095944</reqTime><ReqParam><payAccount>81601035601421001146</payAccount><payAccountName>烟台毛站市场富俚梭锄批发部</payAccountName><recAccount>00060120100006320</recAccount><recAccountName>烟台电叭辙急有限公司</recAccountName><payAmount>1.00</payAmount><currencyType>01</currencyType><orderFlowNo>20191011095944816RY1234</orderFlowNo><payUse>121212</payUse><trsDateTime>20191011095944</trsDateTime></ReqParam></opReq>";
//		System.out.println(opreq.length());
		//查询账户的余额
//		String opreq = "<opReq><opname>"+opname+"</opname><cstNo>"+cstNo+"</cstNo><userNo>"+userNo+"</userNo><serialNo>"+serialNo+"</serialNo><userId>"+userId+"</userId><reqTime>"+reqTime+"</reqTime><ReqParam><accountNo>047101012000060313</accountNo><currencyType>01</currencyType><currIden>0</currIden></ReqParam></opReq>";
		//查询账户的交易明细
		String opreq = "<opReq><opname>"+opname+"</opname><cstNo>"+cstNo+"</cstNo><userNo>"+userNo+"</userNo><serialNo>"+serialNo+"</serialNo><userId>"+userId+"</userId><reqTime>"+reqTime+"</reqTime><ReqParam><accountNo>"+accountNo+"</accountNo><beginDate>"+beginDate+"</beginDate><endDate>"+endDate+"</endDate></ReqParam></opReq>";
		System.out.println("opreq:"+opreq);
		System.out.println("opreq.length:"+opreq.length());
		String signdata = getSignData(opreq);
		System.out.println("签名密文 : "+signdata);
		System.out.println("签名密文长度 : "+signdata.length());


		//报文体
		String messageBody = "<?xml version=\"1.0\" encoding=\"GBK\"?><BankData><Sign><SignedData>"+signdata+"</SignedData><PubKey></PubKey></Sign>"+opreq+"</BankData>";
		System.out.println("报文体长度："+messageBody.length());


//		//组装报文
//		String req = "20191011095944800RY1234000000000enterpriseAccPay00003244<?xml version=\"1.0\" encoding=\"GBK\"?><BankData><Sign><SignedData>"+signdata+"</SignedData><PubKey></PubKey></Sign>"+opreq+"</BankData>";
		//查询账户余额
//		String req = "20230612145517867881234000000000enterpriseQry00000000301<?xml version=\"1.0\" encoding=\"GBK\"?><BankData><Sign><SignedData>"+signdata+"</SignedData><PubKey></PubKey></Sign>"+opreq+"</BankData>";
//		String req = serialNo+"000000000000enterpriseQry"+"00002598"+messageBody;
		//查询明细
//		String req = "2023061309003686788123400000000queryAccHisDetail00000301<?xml version=\"1.0\" encoding=\"GBK\"?><BankData><Sign><SignedData>"+signdata+"</SignedData><PubKey></PubKey></Sign>"+opreq+"</BankData>";
		String req = serialNo+"00000000queryAccHisDetail"+"00002611"+messageBody;
		sendSSLKoal(req);

		//自己验签
//		String v = "<?xml version=\"1.0\" encoding=\"GBK\"?>"+
//						"<msg>"+
//						"<msg_head>"+
//						"	<msg_type>0</msg_type>"+
//						"	<msg_id>1006</msg_id>"+
//						"	<msg_sn>0</msg_sn>"+
//						"	<version>1</version>"+
//						"</msg_head>"+
//						"<msg_body>"+
//						"<origin_data_len desc=\"optional, bytes length\">"+opreq.getBytes(charset).length+"</origin_data_len>"+
//						"<origin_data>"+opreq+"</origin_data>"+
//						"	<signed_data>"+signdata+"</signed_data>"+
//						"</msg_body>"+
//						"</msg>";
//		getVerifyData(v);

	}

	/**
	 * 组装格尔获取签名密文的报文格式
	 * @param orig 签名原文
	 * @return
	 */
	private static String getKoalSignXML(String orig){
		String re = "";
		try {
			re = "<?xml version=1.0 encoding=\"gbk\"?><msg><msg_head><msg_type>0</msg_type><msg_id>1005</msg_id><msg_sn>0</msg_sn><version>1</version></msg_head><msg_body>" +
					"<origin_data_len>" + orig.getBytes(charset).length +"</origin_data_len>" +
					"<origin_data>"+ orig +"</origin_data></msg_body></msg>";
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return re;
	}

	/**
	 * 使用格尔发送ssl请求
	 * @param data 发送报文
	 * @return
	 */
	public static String sendSSLKoal(String data)throws Exception{

		StringBuffer sb = new StringBuffer("");
		HttpURLConnection connection = null;
		BufferedInputStream in = null;
		BufferedOutputStream o = null;
		try {
			System.out.println("上送格尔的数据是："+data);
			connection = (HttpURLConnection) new URL(SSLUrl).openConnection();
			connection.setRequestProperty("content-type", "text/xml; charset="+charset+";");

			connection.setRequestMethod("POST");
			connection.setDoInput(true);
			connection.setDoOutput(true);
			o = new BufferedOutputStream(connection.getOutputStream());
			o.write(data.getBytes(charset));
			o.flush();
			in = new BufferedInputStream(connection.getInputStream());
			byte[] buffer = new byte[1024];
			int len = 0;
			while ((len = in.read(buffer)) != -1) {
				sb.append(new String(buffer, 0, len, "gbk"));
			}
		} catch (Exception e) {
			sb = new StringBuffer("-1");
			e.printStackTrace();
		} finally {
			if (o != null) {
				try {
					o.close();
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
			if (in != null) {
				try {
					in.close();
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
			if (connection != null) {
				try {
					connection.disconnect();
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
		}

		System.out.println("服务器返回的报文：" + sb.toString()+"~~~~~END ");
		return sb.toString();
	}

	/**
	 * 获得签名报文
	 * @param data 签名原文
	 */
	public static String getSignData(String data) throws Exception{
		data = getKoalSignXML(data);

		Socket socket = new Socket(signIP, signport);
		InputStream is = socket.getInputStream();
		InputStreamReader isr = new InputStreamReader(is, charset);
		// 2.获取客户端输出流
		OutputStream dos = socket.getOutputStream();
		System.out.println("连上服务端");
		// 3.向服务端发送消息
		dos.write(data.getBytes());
		dos.flush();
		System.out.println("成功向服务器发送消息");
		// 4.获取输入流，并读取服务器端的响应信息
		BufferedReader br = new BufferedReader(isr);
		String returnInfo = br.readLine();
		System.out.println("服务器端返回数据为：" + returnInfo);
		// 4.关闭资源
		br.close();
		isr.close();
		is.close();
		dos.close();
		socket.close();



		System.out.println("格尔签名返回内容：" + returnInfo+"");
		String signStr = getXMLData(returnInfo,"signed_data").replaceAll("\r\n", "").replaceAll("\n", "");
		System.out.println("格尔返回的密文：" + signStr+"");
		return signStr;
	}

	/**
	 * 获得签名报文
	 * @param data 签名原文
	 */
	public static String getVerifyData(String data) throws Exception{

		Socket socket = new Socket(signIP, signport);
		InputStream is = socket.getInputStream();
		InputStreamReader isr = new InputStreamReader(is, charset);
		// 2.获取客户端输出流
		OutputStream dos = socket.getOutputStream();
		System.out.println("连上服务端");
		// 3.向服务端发送消息
		dos.write(data.getBytes());
		dos.flush();
		System.out.println("成功向服务器发送消息");
		// 4.获取输入流，并读取服务器端的响应信息
		BufferedReader br = new BufferedReader(isr);
		String returnInfo = br.readLine();
		System.out.println("服务器端返回数据为：" + returnInfo);
		// 4.关闭资源
		br.close();
		isr.close();
		is.close();
		dos.close();
		socket.close();



		System.out.println("格尔签名返回内容：" + returnInfo+"");
		return returnInfo;
	}

	/*
	 * 功能：获取XML报文中某个节点的内容
	 */
	private static String getXMLData(String src,String tagName){
		int beginIndex = src.indexOf("<"+tagName+">")+("<"+tagName+">").length();
		int endIndex = src.indexOf("</"+tagName+">");
		return src.substring(beginIndex, endIndex);
	}

}
